#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
/*
  多进程实现不是c或者c++的语言的功能而是linux系统库提供的接口实现


  #include <unistd.h>

  pid_t fork(void);
    功能：通过拷贝父进程得到一个子进程(pid_t本质就是int)
    参数：无
    返回值：成功在父进程中得到子进程的pid，在子进程中的到0，失败返回-1并置位错误码
    注：父子进程是并发的


 #include <sys/types.h>
 #include <unistd.h>

    pid_t getpid(void);
       功能：获取当前进程的进程号
       参数：无
       返回值：当前进程的进程号(这两个函数不会失败)

    pid_t getppid(void);
       功能：获取当前进程的父进程pid号
       参数：无
       返回值：当前进程的父进程pid

*/
/*
 #include <stdlib.h>

void exit(int status);
    功能：停止当前进程，并刷新当前进程打开的标准IO的缓冲区(这个是库函数)
    参数：进程退出时的状态，会将该值与 0377进行位与运算后，返回给回收资源的进程
    返回值：无


#include <unistd.h>

void _exit(int status);
    功能：停止当前进程，不刷新当前进程打开的标准IO的缓冲区(系统内核提供)
    参数：进程退出时的状态，会将该值与 0377进行位与运算后，返回给回收资源的进程
    返回值：无
*/
/*
 #include <sys/types.h>
 #include <sys/wait.h>

 pid_t wait(int *status);
    功能：阻塞回收子进程的资源
    参数：接收子进程退出时的状态，获取子进程退出时的状态与0377进行位与后的结果，如果不愿意接收，可以填NULL
    返回值：成功返回回收资源的那个进程的pid号，失败返回-1并置位错误码

 pid_t waitpid(pid_t pid, int *status, int options);
    功能：可以阻塞也可以非阻塞回收指定进程的资源
    参数1：进程号
        >0:表示回收指定的进程，进程号位pid（常用）
        =0：表示回收当前进程所在进程组中的任意一个子进程
        =-1：表示回收任意一个子进程（常用）
        <-1:表示回收指定进程组中的任意一个子进程，进程组id为给定的pid的绝对值
    参数2：接收子进程退出时的状态，获取子进程退出时的状态与0377进行位与后的结果，如果不愿意接收，可以填NULL
    参数3：是否阻塞
        0：表示阻塞等待           ：waitpid(-1, &status, 0);等价于 wait(&status)
        WNOHANG：表示非阻塞
    返回值：
        >0: 返回的是成功回收的子进程pid号
        =0:表示本次没有回收到子进程
        =-1：出错并置位错误码
*/
int main(int argc, const char *argv[])
{
    pid_t pid = -1;
    pid = fork();
    printf("pid = %d\n", pid);
    // 对pid进程判断
    if (pid > 0)
    {
        // 父进程程序代码
        // 输出当前进程号、子进程号、父进程号
        printf("self pid=%d, child pid = %d, parent pid = %d\n", getpid(), pid, getppid());

        // wait(NULL);        //回收子进程资源,只有回收了子进程资源后，父进程才继续向后执行
        waitpid(-1, NULL, WNOHANG); // 非阻塞回收子进程资源(父进程未成功回收，而子进程就是僵尸进程)
        printf("子进程资源已经回收\n");
    }
    else if (pid == 0)
    {
        // 子进程程序代码
        // 输出当前进程的进程号、父进程进程号
        printf("self pid = %d, parent pid = %d\n", getpid(), getppid());

        printf("11111111111111111111111111111111111"); // 没有加换行，不会自动刷新
        sleep(3);
        printf("self pid = %d, parent pid = %d", getpid(), getppid()); // 僵尸进程的进程号（PID）和父进程号（PPID）与终止前相同
        exit(EXIT_SUCCESS);                                            // 刷新缓冲区并退出进程
        //_exit(EXIT_SUCCESS); // 不刷新缓冲区退出进程
    }
    else
    {
        perror("fork error");
        return -1;
    }

    while (1)
        ; // 防止父进程先结束

    return 0;
}
